本文对Speed up your app进行翻译并研究 下面的翻译只对关键部分进行翻译。原文请参照 http://blog.udinic.com/2015/09/15/speed-up-your-app。

一、优化规则

1.永远使用数据而不是靠感觉来衡量

2.使用低端机型进行测试

3.明确有得必有失,在完成性能优化时,必定需要花费其他样的东西。比如空间

二、Systrace

Systrace是很多程序员不会用的工具,因为其中有很多看不懂的信息,让我们先看看他长什么样子

systrace-1

我们可以通过Android Device Monitor tool 或者命令行进行生成,我们可以在这里发现更多信息。http://developer.android.com/tools/help/systrace.html

在Android Device Monitor tool中点击 systrace-2倒数第二个图标就可以启动

注意图上绿色 黄色 红色的颜色区分,红色代表性能出现了问题

当我们点击该frame的时候

systrace-3

我们可以看到所花费的时间为32ms,超过了frame render的16ms时间。同时,我们可以看到下面各个函数所花费的时间。以此,我们可以发现性能所在的问题

systrace-4

当选择了某个frame的时候,我们可以通过点击m键来查看具体信息,有以下几个信息需要注意

Scheduling delay:定时延迟

A Scheduling delay means that the thread, processing that specific slice, was not scheduled on the CPU for a long time. Therefore, it took longer for this thread to complete. Selecting the longest slice in the frame shows more specific information

Wall duration:任务开始到结束的时间

The Wall duration is the time passed from the moment that slice started until finished. It’s called “Wall duration”, because it’s like looking at a wall clock since the thread has started.

CPU duration:cpu在这个任务上实际花费的时间

The CPU duration is the actual time the CPU spent processing that slice.

一般来说cpu花费时间要小于wall duration

但是如果我们想要得知是什么使得cpu如此繁忙,我们需要使用traceview

三、Traceview

查看每个方法花费时间的工具 http://developer.android.com/tools/debugging/debugging-tracing.html

traceview-1

注意其中有如下属性

Name - The name of the method, along with a color to identify it on the graph above.

Inclusive CPU Time - The time it took the CPU to process that method and its children (i.e. all the methods it called).

Exclusive CPU Time - The time it took the CPU to process that method alone.

Inclusive / Exclusive Real Time - The time that has passed from the moment the method started until completed. Same as “Wall duration” on Systrace.

Calls+Recursion - How many times this method was called, and the amount of recursive calls too.

CPU/Real time per Call - The CPU/Real time it took per call to this method, on average. The other time fields are showing the aggregated time of all calls to a method.

四、Memory Profiling

注意如果图片上存在如下图的向下趋势,则代表是发生了GC

memory-profiling-1

五、Heap dump

主要进行内存泄露的分析

heap-dump-1

同样类似的工具还有LeakCanary

六、Allocation Tracker

根据以上信息,我们可以发现分配太多内存并且可能引起很多GC事件的方法,我们同时也可以发现同一个类的许多短生命周期的实例,针对这个情况,我们可以考虑使用Object pool来减少分配

allocation-tracker-1

allocation-tracker-2

七、一些优化内存的提示

1.当我们讨论性能问题时,枚举通常是不变的话题。枚举会比普通常量更占内存吗?答案是肯定的,但是这是不好的吗?未必。如果你需要强类型带来的安全性,那么就应该使用枚举,而如果你一些可以归类的常量,那么应该使用枚举。

2.自动装箱。自动从原生类型转换到对象,比如int到integer,我们应该避免频繁的自动装箱。

3.HashMap和ArrayMap/SparseArray,和上面第二天一样,HashMap使用对象作为keys,如果我们使用原生int作为关键字,那么他就会自动转换为integer。我们可以考虑使用ArrayMap和SparseArray。性能会更好。

4.时刻关注context,我们往往会在activity中引用context,并且我们需要关注context引用是否被清理,如果未被清理,则会导致activity销毁以后,对象仍然还是存活的。导致了内存泄露。

5.避免非静止的内部类。首先,非静止的内部类在实例化的时候会保有外部类的引用,如果你需要内部类,但是不需要外部类了,就会导致外部类仍然存在于内存中。比如说你在activity中创造一个继承与AsyncTask的非静止内部类,并且执行该异步操作,当我们销毁activity的时候,异步任务仍然会让该activity存活。